package com.example.consistenthash.one;

import com.example.consistenthash.stretagy.Fnv132HashStrategy;
import com.example.consistenthash.stretagy.HashStrategy;

import java.util.*;

public class ConsistentHash1<T> {

    private static HashStrategy hashStrategy;
    private int realNodes = 0;
    private int vitualNodes = 0;
    private static SortedMap<Integer, String> circle = new TreeMap<Integer, String>();// 存储虚拟节点的hash值到真实节点的映射
    private static String[] servers = new String[]{"192.168.0.1:8080", "192.168.0.2:8080", "192.168.0.3:8080", "192.168.0.4:8080"};

    public ConsistentHash1(HashStrategy hashStrategy, int vitualNodes,
                           String... servers) {
        this.hashStrategy = hashStrategy;
        this.realNodes = servers.length;
        this.vitualNodes = vitualNodes;
        for (String server : servers) {
            for (int i = 0; i < vitualNodes; i++) {
                String virtualNodeName = String.format("%s%s%s",server,"VIRTUALNODE",i);
                int hash = hashStrategy.hash(virtualNodeName);
                System.out.println("虚拟节点[" + virtualNodeName + "]被添加, hash值为" + hash);
                circle.put(hash,virtualNodeName);
            }
        }
    }

    public void add(String node) {
        for (int i = 0; i < vitualNodes; i++)
            // 对于一个实际机器节点 node, 对应 vitualNodes 个虚拟节点
            /*
             * 不同的虚拟节点(i不同)有不同的hash值,但都对应同一个实际机器node
             * 虚拟node一般是均衡分布在环上的,数据存储在顺时针方向的虚拟node上
             */
            circle.put(hashStrategy.hash(node.toString() + i), node);
    }

    public void remove(String node) {
        for (int i = 0; i < vitualNodes; i++)
            circle.remove(hashStrategy.hash(node.toString() + i));
    }


    public static String getServer(String key) {
        int hash = hashStrategy.hash(key);
        SortedMap<Integer, String> tailMap = circle.tailMap(hash);
        if (tailMap.isEmpty()) {
            Integer firstKey = circle.firstKey();
            String virtualNodeName = circle.get(firstKey);
            return virtualNodeName.substring(0,virtualNodeName.indexOf("VIRTUALNODE"));
        } else {
            Integer firstKey = tailMap.firstKey();
            String virtualNodeName = tailMap.get(firstKey);
            return virtualNodeName.substring(0,virtualNodeName.indexOf("VIRTUALNODE"));
        }
    }

    public static void main(String[] args) {
        String[] nodes = {"127.0.0.1:8080", "255.255.255.0:9090", "10.36.46.23:6666", "192.168.0.5:8080"};
        ConsistentHash1<Object> consistentHash1 = new ConsistentHash1<>(new Fnv132HashStrategy(), 5, servers);
        for (int i = 0; i < nodes.length; i++) {
            System.out.println("[" + nodes[i] + "]的hash值为" +
                    hashStrategy.hash(nodes[i]) + ", 被路由到结点[" + getServer(nodes[i]) + "]");
        }
    }

}
